package com.simple.car.loader.server.tools;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;

import com.simple.car.loader.server.annotation.Function;
import com.simple.car.loader.server.annotation.Loader;
import com.simple.car.loader.server.dao.RunningInfoDao;
import com.simple.car.loader.server.entity.RunningInfo;

import java.io.File;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Function
public class RunningHandler {

    private Context context;

    private LinkedBlockingDeque<RunningInfo> waiting;

    private LinkedBlockingDeque<RunningInfo> done;

    private ExecutorService executorService;

    private String filePath = "storage/B8FE-C774/Recorder/Normal";

    private Pattern pattern = Pattern.compile("(\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{2}).(mp4|mp4.cpy)");

    private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");

    private WaitingListener waitingListener;

    private ProcessingListener processingListener;

    private DoneListener doneListener;

    @Loader
    private RunningInfoDao runningInfoDao;

    public void init(Context context) {
        this.context = context;
        waiting = new LinkedBlockingDeque<>();
        done = new LinkedBlockingDeque<>();
        executorService = Executors.newSingleThreadExecutor();
    }

    public void handle() {
        initWaiting();
        try {
            RunningInfo runningInfo = waiting.takeFirst();
            do {
                Runnable runnable = process(runningInfo);
                executorService.submit(runnable);
            } while ((runningInfo = waiting.takeFirst()) != null);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private synchronized void initWaiting() {
        List<RunningInfo> runningInfos = runningInfoDao.listByStatue(1);
        runningInfos.removeIf(runningInfo -> {
            if (waiting.contains(runningInfo)) {
                return true;
            }
            waiting.addLast(runningInfo);
            // 等待任务数量监听回调，刷新界面
            if (waitingListener != null) {
                new Handler(Looper.getMainLooper()).post(() -> waitingListener.flush(waiting.size()));
            }
            return true;
        });
    }

    private Runnable process(RunningInfo runningInfo) {
        return () -> {
            // 处理中数量监听回调，刷新界面
            if (processingListener != null) {
                new Handler(Looper.getMainLooper()).post(() -> processingListener.flush(1));
            }
            Date date = runningInfo.getCreateTime();
            LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
            File dir = new File(filePath);
            File[] files = dir.listFiles();
            if (files == null || files.length == 0) return;
            List<Integer> cache = new ArrayList<>();
            for (File file : files) {
                Matcher matcher = pattern.matcher(file.getName());
                if (!matcher.matches()) {
                    continue;
                }
                String group = matcher.group(1);
                LocalDateTime beforeTime = LocalDateTime.parse(group, dateTimeFormatter);
                Duration duration = Duration.between(beforeTime, localDateTime);
                cache.add((int) duration.toMillis());
            }
            int res = -1, index = -1;
            for (int i = 0; i < cache.size(); i++) {
                Integer integer = cache.get(i);
                if (integer < 0) {
                    continue;
                }
                if (res < 0) {
                    res = integer;
                    index = i;
                } else {
                    if (res > integer) {
                        res = integer;
                        index = i;
                    }
                }
            }
            if (index == -1) {
                return;
            }
            File file = files[index];
            save(runningInfo, file);
        };
    }

    private void save(RunningInfo runningInfo, File file) {
        File copy = FileCopy.copy(file);
        if (copy == null) {
            return;
        }
        runningInfo.setFilePath(copy.getAbsolutePath());
        runningInfoDao.updateById(runningInfo);
        done.add(runningInfo);
        // 完成任务数量监听回调，刷新界面
        if (processingListener != null) {
            new Handler(Looper.getMainLooper()).post(() -> processingListener.flush(0));
        }
        if (doneListener != null) {
            new Handler(Looper.getMainLooper()).post(() -> doneListener.flush(done.size()));
        }
    }

    public WaitingListener getWaitingListener() {
        return waitingListener;
    }

    public void setWaitingListener(WaitingListener waitingListener) {
        this.waitingListener = waitingListener;
    }

    public ProcessingListener getProcessingListener() {
        return processingListener;
    }

    public void setProcessingListener(ProcessingListener processingListener) {
        this.processingListener = processingListener;
    }

    public DoneListener getDoneListener() {
        return doneListener;
    }

    public void setDoneListener(DoneListener doneListener) {
        this.doneListener = doneListener;
    }

    public interface WaitingListener {

        void flush(int count);
    }

    public interface ProcessingListener {

        void flush(int count);
    }

    public interface DoneListener {

        void flush(int count);
    }
}
